package com.note.simpleshop.module.order.service;

import com.note.simpleshop.entity.*;
import com.note.simpleshop.exception.IllegalDataException;
import com.note.simpleshop.module.cart.service.CartService;
import com.note.simpleshop.module.cart.vo.CartVo;
import com.note.simpleshop.constant.OrderStatusConstant;
import com.note.simpleshop.constant.PayTypeConstant;
import com.note.simpleshop.exception.NotDataException;
import com.note.simpleshop.module.coupon.service.CouponService;
import com.note.simpleshop.module.coupon.vo.CouponVo;
import com.note.simpleshop.module.goods.service.GoodsSpecService;
import com.note.simpleshop.module.order.dao.OrderRepository;
import com.note.simpleshop.module.order.exception.OrderStatusException;
import com.note.simpleshop.module.order.exception.StockException;
import com.note.simpleshop.module.order.service.OrderItemService;
import com.note.simpleshop.module.order.vo.OrderItemVo;
import com.note.simpleshop.module.order.vo.OrderVo;
import com.note.simpleshop.module.user.service.AddressService;
import com.note.simpleshop.utils.*;
import com.note.simpleshop.vo.PageBean;
import me.hao0.wepay.core.Notifies;
import me.hao0.wepay.core.Wepay;
import me.hao0.wepay.core.WepayBuilder;
import me.hao0.wepay.util.Maps;
import net.bytebuddy.asm.Advice;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class OrderService {
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private AddressService addressService;
    @Autowired
    private CartService cartService;
    @Autowired
    private GoodsSpecService goodsSpecService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private CouponService couponService;
    private Wepay wepay = WepayBuilder.newBuilder(PayUtil.getString("appId"),
            PayUtil.getString("key"), PayUtil.getString("mch_id")).build();
    private String notifyUrl = PayUtil.getString("notifyUrl");
    /***
     * 1.判断商品库存，扣减库存
     * 2.计算商品金额
     * 3.创建订单信息保存
     * 4.清空购物车
     * @param userId
     * @param addressId
     * @param cartIds
     * @param payType
     * @throws NotDataException
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> createOrder(String userId, String addressId, List<String> cartIds, List<String> couponIds,String payType,String ip) throws NotDataException,IllegalDataException,StockException {
        Map<String,Object> mapRes=new HashMap<String, Object>();
            if (!PayTypeConstant.set.contains(payType)) {
                throw new NotDataException("支付方式不支持");
            }
            TbAddress address = addressService.findByIdAndUserId(addressId, userId);
            if (address == null) {
                throw new NotDataException("地址信息不存在");
            }
            //查询出购物车中商品信息
            List<CartVo> cartVoList = cartService.findByCardIds(userId, cartIds);
            //用户购物车是否有信息
            if (cartVoList.size()<1) {
                throw new NotDataException("无购物信息");
            }
            //判断优惠券合法
            //判断优惠券是否属于该用户
            List<CouponVo> couponVoList=couponService.findByCoupon(userId,couponIds);
            if(couponIds.size()!=couponVoList.size()) {
                throw new NotDataException("优惠券信息有误");
            }
            //判断优惠券是否互斥
            Integer notMutex=0;
            Integer mute=0;
            Integer dicount=0;
            Integer quato=0;
            for(CouponVo couponVo:couponVoList) {
                if(TbCoupon.NOT_NUTEX.equals(couponVo.getOverlying())) {
                    notMutex++;
                }
                else {
                    mute++;
                }
                //折扣卷和满减卷为互斥卷
                if(TbCoupon.DISCOUNT.equals(couponVo.getPreferentialWay())) {
                    dicount++;
                }
                else {
                    quato++;
                }
            }
            //两种情况，1.互斥卷大于等于1且非互斥卷大于等于1;2互斥卷大于1
            if((mute>0&&notMutex>0)||mute>1) {
                throw new IllegalDataException("优惠券信息有误");
            }
            //折扣卷和额度卷不能同时使用
            if(dicount>0&&quato>0) {
                logger.info("折扣卷和满减卷不能同时使用");
                throw new IllegalDataException("折扣卷和满减卷不能同时使用");
            }
            //确认商品库存
            //计算商品总价和折后价格
            //创建订单orderItem
            List<TbOrderItem> orderItemList = new ArrayList<TbOrderItem>();
            BigDecimal discountTotalMoney = new BigDecimal(0);
            BigDecimal totalMoney = new BigDecimal(0);
            String orderId = IdGenerator.id();
            for (CartVo cartVo : cartVoList) {
                //清除购物车
                cartService.deleteCart(userId,cartVo.getId());
                TbOrderItem orderItem = new TbOrderItem();
                orderItem.setId(IdGenerator.id());
                orderItem.setDiscount(cartVo.getGoodsSpec().getDiscount());
                orderItem.setGoodsName(cartVo.getGoods().getName());
                orderItem.setNum(cartVo.getNum());
                orderItem.setMarketPrice(cartVo.getGoodsSpec().getMarketPrice());
                orderItem.setSalePrice(cartVo.getGoodsSpec().getSalePrice());
                orderItem.setOrderId(orderId);
                //更新库存
                Integer stock=cartVo.getGoodsSpec().getStock()-cartVo.getNum();
                String goodsSpecId=cartVo.getGoodsSpecId();
                goodsSpecService.updateStock(stock,goodsSpecId);
                //保存商品部分信息
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("goods_id", cartVo.getGoods().getId());
                map.put("name", cartVo.getGoods().getName());
                map.put("intro", cartVo.getGoods().getIntro());
                map.put("thumbnail", cartVo.getGoods().getThumbnail());
                orderItem.setDetail(GsonUtil.toGson(map));
                //保存item信息
                orderItemService.save(orderItem);
                orderItemList.add(orderItem);
                BigDecimal num = new BigDecimal(cartVo.getNum());
                BigDecimal discount = new BigDecimal(cartVo.getGoodsSpec().getDiscount());
                BigDecimal price = cartVo.getGoodsSpec().getSalePrice();
                discountTotalMoney = num.multiply(discount).multiply(price).add(discountTotalMoney);
                totalMoney = num.multiply(price).add(totalMoney);
                if (cartVo.getNum() > cartVo.getGoodsSpec().getStock()) {
                    logger.info("insufficient inventory goodsId={},goodsSpecId={}",cartVo.getGoods().getId(),cartVo.getGoodsSpec().getId());
                    throw new StockException("库存不足");
                }
            }
            //校验是否满足额度,如订单150元，但是有两张可以同时使用的100优惠券，那么订单金额为0
            BigDecimal payMoney=discountTotalMoney;
            for(CouponVo couponVo:couponVoList) {
                if(couponVo.getQuota().compareTo(discountTotalMoney)<0) {
                    //多张折扣卷折上折
                    if(TbCoupon.DISCOUNT.equals(couponVo.getPreferentialWay())) {
                        payMoney=payMoney.multiply(new BigDecimal(couponVo.getDiscount()));
                    }
                    else {
                        payMoney=payMoney.subtract(couponVo.getQuota());
                        //如果总金额小于0，订单应付金额为0元
                        if(payMoney.compareTo(new BigDecimal(0))<=0) {
                            payMoney=new BigDecimal(0);
                            break;
                        }
                    }
                }
                else{
                    logger.info("createOrder couponId={}, quota={},discountTotalMoney={}",couponVo.getCouponId(),couponVo.getQuota(),discountTotalMoney);
                    throw new IllegalDataException("存在优惠券满减额度小于订单额度");
                }
            }
            String orderNo = OrderUtils.generateOrderNo();
            TbOrder order = new TbOrder();
            order.setId(orderId);
            order.setReceiver(address.getReceiver());
            order.setAddress(address.getAddress());
            order.setPhone(address.getPhone());
            order.setOrderAmount(discountTotalMoney);
            order.setOrderNo(orderNo);
            //如果等于0免单
            if(discountTotalMoney.compareTo(new BigDecimal(0))==0) {
                order.setOrderStatus(TbOrder.ORDER_STATUS1);
            }
            else {
                order.setOrderStatus(TbOrder.ORDER_STATUS0);
            }
            order.setOrderTime(DateUtil.getTimestamp());
            //30分钟过期
            order.setExpireTime(DateUtil.after(30*60*1000l));
            order.setPayType(payType);
            order.setUserId(userId);
            // 微信支付请求
//            PayRequest request = new PayRequest();
//            request.setBody("商品支付交易：订单号"+orderNo);
//            request.setClientId(ip);
//            request.setTotalFee(discountTotalMoney.multiply(new BigDecimal(100)).intValue());
//            request.setNotifyUrl(notifyUrl);
//            request.setOutTradeNo(orderNo);
//            request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
//            request.setTimeExpire(DateUtil.getSmoothTime((order.getExpireTime())));
//            AppPayResponse resp = wepay.pay().appPay(request);
//            prepareId= resp.getPrepayId();
            order.setPrepareId("");
            mapRes.put("prepareId","");
            mapRes.put("orderNo",orderNo);
            orderRepository.save(order);
        return mapRes;
    }
    public String callbackConfirmOrder(String str)
    {
        Notifies notifies = wepay.notifies();
        if (StringUtils.isNotBlank(str))
        {
            Map<String, Object> resultMap = Maps.toMap(str);
            if (notifies.verifySign(resultMap))
            {
                String out_trade_no = (String) resultMap.get("out_trade_no");
                // 更改订单支付状态
                orderRepository.updateOrderStatus(TbOrder.ORDER_STATUS1,out_trade_no);
                logger.info("修改订单状态成功----out_trade_no={}",out_trade_no);
                return notifies.ok();
            } else
            {
                logger.info("签名验证失败支付异常:message={}",str);
                return notifies.notOk("签名验证失败支付异常");
            }
        } else
        {
            logger.info("签名验证失败支付异常:message={}",str);
            return notifies.notOk("没有读取微信返回的xml字符串信息");
        }
    }
    public PageBean findByPage(String userId, String orderStatus, Integer pageNumber) throws OrderStatusException
    {
        //判断订单状态是否合法

        if (pageNumber == null) {
            pageNumber = 0;
        }
        else
        {
            pageNumber=pageNumber-1;
        }
        if(!OrderStatusConstant.set.contains(orderStatus))
        {
            throw new OrderStatusException("orderStatus值错误");
        }
        Sort sort = new Sort(Sort.Direction.DESC, "addTime");
        PageRequest pageRequest = new PageRequest(pageNumber, 20, sort);
        Specification<TbOrder> specification=new Specification<TbOrder>() {
            private static final long serialVersionUID = 1L;
            @Override
            public Predicate toPredicate(Root<TbOrder> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(criteriaBuilder.equal(root.get("isDelete"), TbCart.IS_DELEETE0));
                predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
                if(!OrderStatusConstant.ORDER_ALL.equals(orderStatus))
                {
                    predicates.add(criteriaBuilder.equal(root.get("orderStatus"), orderStatus));
                }
                return  criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        Page<TbOrder> page = orderRepository.findAll(specification,pageRequest);
        List<TbOrder> orderlist=page.getContent();
        List<OrderVo> orderVoList=new ArrayList<OrderVo>();
        for(TbOrder order:orderlist) {
            OrderVo orderVo= OrderVo.newInstance(order);
            List<OrderItemVo> orderItemList=orderItemService.findByOrderId(orderVo.getId());
            orderVo.copy(orderItemList);
            orderVoList.add(orderVo);
        }
        PageBean<OrderVo> pageBean=new PageBean(page.getTotalPages(),(int)page.getTotalElements(),page.isFirst(),page.isEmpty(),page.getNumber(), orderVoList);;
        return pageBean;
    }
}
